(function (window) {
  // 传递进来的匿名函数 称作 excutor：执行器函数(同步)
  function Promise (excutor) {
    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'

    // 将当前promise对象保存起来
    const _this = this
    // 给promise对象指定status属性，初始值为pending
    this.status = PENDING
    // 给promise对象指定一个用于存储结果数据的属性
    this.data = null
    // 每个元素的结果 {onResolved() {}, onRejected() {}}
    this.callbacks = []

    function resolve (vlaue) {
      // this ==== window
      // 如果当前状态不是pending 直接结束
      if (_this.status !== PENDING) return
      // 将状态改为 resolved
      _this.status = RESOLVED
      // 保存value数据
      _this.data = vlaue

      // 如果有待执行的callback函数，立即异步执行回调函数 onResolved
      // 回调函数可能并不会第一时间被绑定
      // 什么时候不会第一时间绑定？当excutor函数体中的方法为同步代码callbacks就是空的
      //    => 这就属于先改状态再指定回调

      // 当我们执行resolve的时候 什么情况下callbacks中存在函数
      // 当excutor不会马上被执行（存在异步代码或者需要等待一段时间被调用）
      // 此时同步代码优先执行 如果存在链式方式就会去执行链式方法 当链式方法被执行的时候会检测当前的状态
      // 如果为pending，就会把传入的回调函数存在callbacks中 此时 callbacks中就不为空了 当时间一到执行resolve
      // 就是去执行缓存起来的函数

      if (_this.callbacks.length > 0) {
        // 放入队列 因为then函数中的回调是个异步方法
        setTimeout(() => {
          // callbacksObj 两个回调函数
          _this.callbacks.forEach(callbacksObj => {
            // 执行回调函数 还需要改变要返回的新的promise的状态
            callbacksObj.onResolved(vlaue)
          })
        })
      }
    }
    function reject (reason) {
      // 如果当前状态不是pending 直接结束
      if (_this.status !== PENDING) return
      // 将状态改为 rejected
      _this.status = REJECTED
      // 保存reason数据
      _this.data = reason
      // 如果有待执行的callback函数，立即异步执行回调函数 onRejected
      if (_this.callbacks.length > 0) {
        // 放入队列 因为then函数中的回调是个异步方法
        setTimeout(() => {
          // callbacksObj 两个回调函数
          _this.callbacks.forEach(callbacksObj => {
            callbacksObj.onRejected(reason)
          })
        })
      }
    }

    try {
      // 立即同步执行excutor
      excutor(resolve, reject)
    } catch (error) {
      // 如果执行器(使用者传入的回掉函数)抛出异常，promise对象变为rejected状态
      reject(error)
    }
  }
  /* 
  Promise上的原型方法
  */
  // 指定成功和失败的回调函数 返回一个新的promise对象  onResolved：成功的回调  onRejected：失败的回调
  Promise.prototype.then = function (onResolved, onRejected) {
    const _this = this

    // 向后传递成功的value
    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }
    // 指定默认的失败的回调(实现promise 异常穿透的关键点)
    // 向后传递失败的reason 要么传递一个throw 或者 失败的promise
    if (typeof onRejected !== 'function') {
      onRejected = reason => { throw reason }
    }

    // 返回一个新的promise对象
    // 我们需要判断 该调用那个状态下的回调函数
    return new Promise((resolve, reject) => {
      // 指定：有可能要调用 也有可能要保存(pending) 需要判断状态
      function handle (callback) {
        try {
          // 上一次promise的状态 成功了就执行 onResolved 否则 失败执行 onRejected
          const result = callback(_this.data)
          // 如果是一个promise
          if (result instanceof Promise) {
            // 更为简洁处理
            result.then(resolve, reject)
          } else { // 非promise
            resolve(result)
          }
        } catch (error) {
          reject(error)
        }
      }

      // 可能.then的时候 this.status 为别的状态
      if (_this.status === 'pending') {
        _this.callbacks.push({
          // value 状态改变 传递的值 _self.data 也可以取到
          onResolved (value) {
            handle(onResolved)
          },
          onRejected (reason) {
            handle(onRejected)
          }
        })
      } else if (_this.status === 'resolved') {
        // 如果当前是resolved状态，异步执行onResolved并改变return的promise状态
        setTimeout(() => {
          handle(onResolved)
        })
      } else { // rejected
        setTimeout(() => {
          handle(onRejected)
        })
      }
    })
  }

  // 指定失败的回调函数 返回一个新的promise对象
  Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
  }
  /* 
    Promise函数对象上的方法
  */
  // 返回一个指定结果的promise对象
  // 调用Promise.resolve 有可能成功 有可能失败
  // 失败：传递一个失败的promise 就是失败
  Promise.resolve = function (value) {
    // 返回一个成功/失败的promise
    return new Promise((resolve, reject) => {
      // value 是promise
      // 使用value的结果作为promise的结果
      if (value instanceof Promise) {
        value.then(resolve, reject)
      } else { // value 不是promise => promie变为成功 数据是value
        resolve(value)
      }
    })
  }
 
  // 返回一个指定reason的失败的promise
  // 调用Promise.reject 必然返回的是一个失败的promise
  Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

  // 返回一个promise，只有当所有的promise都成功时才成功，否则只要有一个失败的就失败
  // 数组中有可能非promise的值 那么直接成功
  Promise.all = function (promises) {
    // 用来保存所有成功的value的数据
    let values = new Array(promises.length)
    // 用来保存成功的promise数量
    let resolvedCount = 0
    return new Promise((resolve, reject) => {
      // 遍历promise获取每个promise的结果
      promises.forEach((p, index) => {
        // p.then
        // 解决非promise的值 通过给p包装成promise
        Promise.resolve(p).then(value => {
          // 成功的数量+1
          resolvedCount++
          // p成功，将成功的value保存value
          // 这个地方存储promise成功返回的value值 不可以使用数组 因为promise的执行可能存在异步函数 无法确定谁先那个promise返回的值被先添加到数组中 无法存储的values值的顺序与传递进来的promises的顺序一致
          values[index] = value
          // 如果全部成功了 将return的promise的状态改为成功
          // 知道promise全部成功了 才把状态改变 只有全部成功状态才是resolved
          if (resolvedCount === promises.length) { // 全部成功
            resolve(values)
          }
        }, reason => { // 只要一个失败了 return的promise就失败
          reject(reason)
        })
      })
    })
  }

  // 返回一个promise，其结果由第一个完成的promise决定
  Promise.race = function (promises) {
    // 返回一个promise
    return new Promise((resolve, reject) => {
      promises.forEach(p => {
        Promise.resolve(p).then(value => { // 一旦有成功的，将return的promise变为成功
          resolve(value)
        }, reason => { // 否则失败
          reject(reason)
        })
      })
      // 只要成功了 或者 失败了 以后再执行 状态也是不会再执行的
    })
  }

  // 返回一个promise对象 它在指定的时间后才确定结果
  Promise.resolvedDelay = function (value, time) {
    // 返回一个成功/失败的promise
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (value instanceof Promise) {
          value.then(resolve, reject)
        } else {
          resolve(value)
        }
      }, time)
    })
  }

  // 返回一个promise对象，它在指定的时间后状态为rejected
  Promise.rejectedDelay = function (reason, time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(reason)
      }, time);
    })
  }
  window.Promise = Promise
})(window)